function documentReady() {

    createOptionsButton();
}

function createOptionsButton() {

    var leftPanelHeader = $('#leftPanelHeader');
    var leftPanelHeaderOffset = leftPanelHeader.offset();
    var leftPanelHeaderHeight = leftPanelHeader.height();

    var optionsButton = makeEl('a').attr( { 'href': 'javascript:void(0)', 'class': 'smallText absolute', 'id': 'optionsButton' } )
                                   .text('Options')
                                   .click( handleOptionsButtonClick );

    leftPanelHeader.append( optionsButton );

    optionsButton.css( { 'left': leftPanelHeaderOffset.left + leftPanelHeader.width() - optionsButton.width() - 5,
                         'top': leftPanelHeaderOffset.top + ( ( leftPanelHeaderHeight - optionsButton.height() ) / 2 ) } );
}

function handleOptionsButtonClick( p ) {

    var contextMenu = isContextMenu();

    if( contextMenu && mouseOnElement( { el: contextMenu, x: p.pageX, y: p.pageY } ) ) { return; }

    else if( contextMenu ) { contextMenu.empty().remove(); }

    else {

        makeContextMenu( { container: $('#leftPanelHeader'),
                           menuItems: optionsMenuItems,
                           x: p.pageX, y: p.pageY } );
    }
}

function createSourceTreeItem( p ) {

    return makeEl('div').attr( { 'treeId': p.id, 'class': 'bottomBorder padding10p' } )
                        .bind( 'mouseup', { treeId: p.id }, handleSourceTreeItemClick )
                        .mouseover( addContextHighlight )
                        .mouseout( removeContextHighlight )
                        .append( makeEl('div').attr( { 'class': 'fLeft' } ).text( p.name ),
                                 makeEl('div').attr( { 'class': 'fRight' } ).text( p.creationDate ),
                                 makeEl('div').attr( { 'class': 'clear' } ) );
}

function handleSourceTreeItemClick( p ) {

    var contextMenu = isContextMenu();

    if( contextMenu && mouseOnElement( { el: contextMenu, x: p.pageX, y: p.pageY } ) ) { return; }

    else if( contextMenu ) { contextMenu.empty().remove(); }

    else {

        if( p.which != 3 ) {

            globals.requestingTreeForMainPanel = true;

            ajaxGetTree( { treeId: p.data.treeId, type: 'source', success: renderTreeInMainPanel } );

        } else {

            makeContextMenu( { container: $('#leftPanel'), 
                               menuItems: [ { text: 'Remove Source Tree',
                                              func: ajaxDeleteSourceTree,
                                              params: { treeId: p.data.treeId } } ],
                               x: p.pageX, y: p.pageY } );
        }
    }
}


function removeContextMenu( p ) {

    var contextMenu = isContextMenu();

    if( contextMenu && mouseOnElement( { el: contextMenu, x: p.pageX, y: p.pageY } ) ) { return; }

    else if( contextMenu ) { contextMenu.empty().remove(); }
}

function handleMainPanelClick( p ) { removeContextMenu(p); }

function handleLeftPanelClick( p ) {
    
    if( mouseOnElement( { el: $('#sourceTreeInfoContainer'), x: p.pageX, y: p.pageY } ) ||
        mouseOnElement( { el: $('#optionsButton'), x: p.pageX, y: p.pageY } ) ) { return; } else { removeContextMenu(p); } }

function renderTreeInMainPanel( response ) {
    
    globals.requestingTreeForMainPanel = false;

    var responseObj = eval( "(" + response + ")" );

    var localGlobal = globals;
    var localConfig = config;
    var treeInfo = localGlobal.mainPanelTreeInfo;
    var labelInfo = localGlobal.labelInfo;
   
    treeInfo.tree = responseObj.tree; 
    treeInfo.id = responseObj.id;
    treeInfo.type = responseObj.type;

    delete ajaxResponse; delete responseObj;
   
    //traverse the tree for information needed before rendering 
    treeInfo.meta = getTreeInfo( { clade: treeInfo.tree } );
   
    var mainPanel = $('#mainPanel'); 
    var mainPanelWidth = mainPanel.width();
    var mainPanelHeight = mainPanel.height();

    setMainPanelCanvas( { localGlobal: localGlobal,
                          localConfig: localConfig,
                          mainPanelInfo: { width: mainPanelWidth, height: mainPanelHeight },
                          containerId: 'raphaelContainer' } );

    var firstTip = { x: ( localConfig.generationSeparation.value * ( localGlobal.mainPanelTreeInfo.meta.generations - 1 ) + 20 + localConfig.canvasBuffer.value ), //add 20 for root
                     y: ( ( mainPanelHeight / 2 ) ) };


    var pathString = new StringBuffer();

    localGlobal.labelInfo.labelsToAdd = [];
    localGlobal.labelInfo.labels = {};
    
    preRender( { clade: treeInfo.tree,
                 currentTip: firstTip,
                 scaleValue: { x: 1, y: 1 },
                 generationSeparation: localConfig.generationSeparation.value,
                 nodeSeparation: localConfig.nodeSeparation.value,
                 scaling: 'unscaled',
                 pathWidth: localConfig.pathWidth.value,
                 fontSize: localConfig.fontSize.value,
                 buttonRadius: localConfig.buttonRadius.value,
                 labelBuffer: localConfig.labelBuffer.value,
                 pathStrings: pathString,
                 labels: labelInfo.labels,
                 labelsToAdd: labelInfo.labelsToAdd,
                 renderInfoFun: gatherMainPanelCladeInfo,
                 canvas: localGlobal.mainPanelCanvas,
                 generation: treeInfo.meta.generations } );


    if( labelInfo.labelsToAdd.length ) {

        setTimeout( addMainPanelLabels, 0,
                    { labels: labelInfo.labelsToAdd,
                      labelHolder: labelInfo.labels,
                      canvas: localGlobal.mainPanelCanvas,
                      scaling: 'unscaled',
                      localConfig: { labelColor: localConfig.labelColor.value,
                                     fontSize: localConfig.fontSize.value,
                                     fontFaily: localConfig.fontFamily.value,
                                     buttonRadius: localConfig.buttonRadius.value,
                                     labelBuffer: localConfig.labelBuffer.value },
                                     index: 0 } );
    }


    createTreePath( { string: pathString.toString(),
                      canvas: localGlobal.mainPanelCanvas,
                      attr: { stroke: localConfig.cladeColor.value,
                              "stroke-width": localConfig.pathWidth.value } } );

    mainPanel.scrollLeft( $('#raphaelContainer').width() - mainPanelWidth + localGlobal.scrollBarWidth );

    return treeInfo;
}


function getTreeInfo( p ) {

    var myTraversal = p.clade.length;
    var tips = 0;
    var myGeneration = 1;
    var myTipLabel = '';

    if( p.clade.children.length ) {

        var returnedInfo = [];
        var longestTraversal = 0;
        var longestTipLabel = 0;
        var mostGenerations = 0;

        for( var i = 0, ii = p.clade.children.length; i < ii; i++ ) {

            returnedInfo.push( getTreeInfo( { 'clade': p.clade.children[i] } ) );

            if( returnedInfo[i].longestTipLabel.length > longestTipLabel ) {
                longestTipLabel = returnedInfo[i].longestTipLabel;
            }

            if( returnedInfo[i].traversal > longestTraversal ) {

                longestTraversal = returnedInfo[i].traversal;
            }

            if( returnedInfo[i].generations > mostGenerations ) {

                mostGenerations = returnedInfo[i].generations;
            }

            tips = tips + returnedInfo[i].tips;
        }

        myTraversal = myTraversal + longestTraversal;
        myGeneration = myGeneration + mostGenerations;
        myTipLabel = longestTipLabel;

    } else {

        if( p.clade.name ) { myTipLabel = p.clade.name; }

        tips = tips + 1;
    }

    return { traversal: myTraversal,
             generations: myGeneration,
             longestTipLabel: myTipLabel,
             tips: tips };
}


function setMainPanelCanvas( p ) {

    if( !p.localGlobal.mainPanelCanvas ) {

        p.localGlobal.mainPanelCanvas = Raphael( p.containerId, 300, 100 );

    } else {

        p.localGlobal.mainPanelCanvas.clear();

        var dragInfo = p.localGlobal.draggingInfo;
        dragInfo.hidingPath = undefined;
        dragInfo.graftingPath = undefined;
        dragInfo.mostRecentClade = undefined;
    }

    var treeInfo = p.localGlobal.mainPanelTreeInfo.meta;

    var treeWidth = ( p.localConfig.generationSeparation.value * ( treeInfo.generations - 1 ) );

    var longestLabel = getWordLength( { word: treeInfo.longestTipLabel, size: p.localConfig.fontSize.value, canvas: p.localGlobal.mainPanelCanvas } );

    treeInfo.longestTipLabel = longestLabel.width;
    treeInfo.rootLabelLength = ( p.localGlobal.mainPanelTreeInfo.tree.name ) ? getWordLength( { word: p.localGlobal.mainPanelTreeInfo.tree.name, canvas: p.localGlobal.mainPanelCanvas } ).width : 0;

    var width = treeWidth + 
                ( p.localConfig.canvasBuffer.value * 2 ) +
                ( p.localConfig.labelBuffer.value ) +
                ( p.localGlobal.scrollBarWidth ) +
                ( treeInfo.longestTipLabel ) +
                ( treeInfo.rootLabelLength ) + 20; //add the 20 for the root

    var height = ( ( treeInfo.tips - 1 ) * p.localConfig.nodeSeparation.value ) + ( longestLabel.height * 2 ) + p.mainPanelInfo.height;

    if( width < p.mainPanelInfo.width ) { width = p.mainPanelInfo.width; }
    if( height < p.mainPanelInfo.height ) { height = p.mainPanelInfo.height; }

    $('#' + p.containerId).width( width ).height( height );

    p.localGlobal.mainPanelCanvas.setSize( width, height );
}

function handleDeleteSourceTreeResponse( response ) {

    if( response == 'referenceError' ) {

        alert('The source tree could not be deleted as there are references to it.');

    } else {

        $('div[treeId=' + response + ']').hide( 'slow', removeSourceTreeItem );    

        var localGlobal = globals;
        if( localGlobal.mainPanelTreeInfo.id == response ) { localGlobal.mainPanelCanvas.clear(); }
    }
}

function removeSourceTreeItem() { $(this).empty().remove(); }











////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function onDocumentReady() {

    $('#tabs').tabs();

    addShadowboxKeyPressHandlers();

    createAddSourceTreeButton();

    $('#mainPanel').mouseup( handleMainPanelMouseUp );
    $('#rightPanel').mouseup( handleRightPanelMouseUp );
}

function handleMainPanelMouseUp( p )  {

    var contextMenu = isContextMenu();
    
    if( contextMenu ) {

        if( !mouseOnElement( { el: contextMenu, x: p.pageX, y: p.pageY } ) ) {
            contextMenu.empty().remove();
        }
    }
}

function handleRightPanelMouseUp( p ) {

    var target = $(p.target);

    if( target.hasClass('treeHeader') ) { return; }

    var contextMenu = isContextMenu();

    if( contextMenu ) { contextMenu.empty().remove(); }
}

function createTreeInfoHeader( p ) {

    var divId = ( p.type == 'saved' )
        ? 'saved' + p.id
        : p.id;

    return makeEl('div').attr( { 'id': divId, 'class': 'bottomBorder treeWrapper' } ).append(
             makeEl('div').attr( { 'class': 'treeHeader padding10p' } )
                          .bind( 'mouseup', { id: p.id, divId: divId, type: p.type }, handleTreeHeaderClick )
                          .mouseover( addContextHighlight )
                          .mouseout( removeContextHighlight ).append(
                 makeEl('div').attr( { 'class': 'fLeft' } ).text( p.name ),
                 makeEl('div').attr( { 'class': 'fRight' } ).text( p.creationDate ),
                 makeEl('div').attr( { 'class': 'clear' } ) ) );
}





function handleDeleteSavedCladeResponse( response ) {

    $('#saved'+ response).hide('slow', removeTreeInfoHeader );
}

        
function handleTreeHeaderClick( p ) {
    
    var menuInfo = ( $('#saved').is(':visible') )
        ? { text: 'Delete Saved Clade', func: ajaxDeleteSavedClade, params: { savedCladeId: p.data.id } }
        : { text: 'Delete Tree', func: ajaxDeleteTree, params: { treeId: p.data.id } };


   if( p.which == 3 ) {
    
       var contextMenu = isContextMenu();

       if( contextMenu ) {

           contextMenu.empty().remove();

       } else {

           makeContextMenu( { container: $('#rightPanel'), 
                               menuItems: [ { text: menuInfo.text,
                                              func: menuInfo.func,
                                              params: menuInfo.params } ],
                                   x: p.pageX, y: p.pageY } );
       }

   } else {

       //hideVisualGraftingAnnotations();

       hideShownTrees();

       if( $('#' + p.data.divId).children('div').length == 1 ) {

           p.data.success = handleReceivedTreeForRightPanel;

           ajaxRetrieveTree( { data: p.data } );

       } else if( $('#renderButton' + p.data.id).is(':hidden') ) {

           if( globals.mainPanelTreeInfo.id != p.data.id ) {
               $('#renderButton' + p.data.id).show('slow');
           }

           $('#visualWrapper' + p.data.id).show('slow');

       } else {
           
           $('#renderButton' + p.data.id).hide('slow');
           $('#visualWrapper' + p.data.id).hide('slow');
       }
    }
}


function hideShownTrees() {

    var currentlyOpen = $('#rightPanel .visualWrapper:visible');

    if( currentlyOpen.length ) {

        currentlyOpen.hide('slow');
        currentlyOpen.prev('div').hide('slow');
    }
}


function ajaxRetrieveTree( p ) {

    $.ajax( { url: makeAjaxURL( { 'argList': [ 'retrieveTree' ] } ),
                  type: "POST",
                  data: { id: p.data.id, type: p.data.type },
                  success: p.data.success } );
}




function handleReceivedTreeForMainPanel( ajaxResponse ) {
    
    globals.requestingNewTree = false;

    var localGlobal = globals;
    var localConfig = config;
    
    var responseObj = eval( "(" + ajaxResponse + ")" );
    
    localGlobal.mainPanelTreeInfo.tree = responseObj.tree;
    localGlobal.mainPanelTreeInfo.id = responseObj.id;
    localGlobal.mainPanelTreeInfo.type = responseObj.type;

    delete ajaxResponse;

    if( responseObj.type == 'saved' ) {
        $('#renderButtonsaved' + localGlobal.mainPanelTreeInfo.id).hide('slow');
    } else {
        $('#renderButton' + localGlobal.mainPanelTreeInfo.id).hide('slow');
    }
    
    localGlobal.mainPanelTreeInfo.tree.isRoot = true;

    //if canvas does not exist yet - create it
    if( !localGlobal.mainPanelCanvas ) {
        localGlobal.mainPanelCanvas = Raphael( 'raphaelContainer', 300, 100 );
        $('#mainPanel').mousemove( handleMainPanelMouseMove );
    } else {
        localGlobal.mainPanelCanvas.clear();
        localGlobal.cladeButton = undefined;
    }

    //traverse the tree for information needed before rendering 
    localGlobal.mainPanelTreeInfo.meta = getTreeInfo( { clade: localGlobal.mainPanelTreeInfo.tree } );

    setMainPanelCanvasSize( { localGlobal: localGlobal,
                              localConfig: localConfig,
                              container: $('#raphaelContainer') } );

    var firstTip = { x: ( localConfig.generationSeparation.value * ( localGlobal.mainPanelTreeInfo.meta.generations - 1 ) + 20 + localConfig.canvasBuffer.value ), //add 20 for root
                     y: ( ( $('#rightPanel').height() / 2 ) ) };

    var pathString = new StringBuffer();
    
    var labelInfo = localGlobal.labelInfo;

    localGlobal.labelInfo.labelsToAdd = [];
    localGlobal.labelInfo.labels = {};
    
    preRender( { clade: localGlobal.mainPanelTreeInfo.tree,
                 currentTip: firstTip,
                 scaleValue: { x: 1, y: 1 },
                 generationSeparation: localConfig.generationSeparation.value,
                 nodeSeparation: localConfig.nodeSeparation.value,
                 scaling: 'unscaled',
                 pathWidth: localConfig.pathWidth.value,
                 fontSize: localConfig.fontSize.value,
                 buttonRadius: localConfig.buttonRadius.value,
                 labelBuffer: localConfig.labelBuffer.value,
                 pathStrings: pathString,
                 labels: labelInfo.labels,
                 labelsToAdd: labelInfo.labelsToAdd,
                 renderInfoFun: gatherMainPanelCladeInfo,
                 canvas: localGlobal.mainPanelCanvas,
                 generation: localGlobal.mainPanelTreeInfo.meta.generations } );


    if( labelInfo.labelsToAdd.length ) {

        setTimeout( addMainPanelLabels, 0,
                    { labels: labelInfo.labelsToAdd,
                      labelHolder: labelInfo.labels,
                      canvas: localGlobal.mainPanelCanvas,
                      scaling: 'unscaled',
                      localConfig: { labelColor: localConfig.labelColor.value,
                                     fontSize: localConfig.fontSize.value,
                                     fontFaily: localConfig.fontFamily.value,
                                     buttonRadius: localConfig.buttonRadius.value,
                                     labelBuffer: localConfig.labelBuffer.value },
                                     index: 0 } );
    }


    createTreePath( { string: pathString.toString(),
                      canvas: localGlobal.mainPanelCanvas,
                      attr: { stroke: localConfig.cladeColor.value,
                              "stroke-width": localConfig.pathWidth.value } } );

    var mainPanel = $('#mainPanel');
    mainPanel.scrollLeft( $('#raphaelContainer').width() - mainPanel.width() + localGlobal.scrollBarWidth );
}

function getTreeForMainPanel( p ) {

    globals.requestingNewTree = true;

    ajaxRetrieveTree( p );
}

function initializeDragGrafting( p ) {

    var raphaelContainer = $('#raphaelContainer' + p.data.divId);
    
    raphaelContainer.draggable( { containment: 'document', 
                                  drag: handleTreeDrag,
                                  start: setTreeDragging,
                                  stop: unsetTreeDragging } );

    $('#rightPanel').removeClass('scrollable');
}

function verticalScroll( p ) {

    var localGlobal = globals;

    if( ( localGlobal.scrollEvents.down || localGlobal.scrollEvents.up ) && localGlobal.draggingInfo.currentlyDragging ) {

        p.mainPanel.scrollTop( p.mainPanel.scrollTop() + p.scroll );

        setTimeout( verticalScroll, 250, { mainPanel: p.mainPanel, scroll: p.scroll } );
    }
}

function checkForMainPanelScroll( p ) {

    var mainTreeContainer = $('#raphaelContainer');

    p.mainPanelInfo.bottom = p.mainPanelInfo.top + p.mainPanelInfo.height;
    p.movingTreeInfo.bottom = p.movingTreeInfo.top + p.movingTreeInfo.height;

    //if there's a vertical scrollbar
    if( mainTreeContainer.height() > p.mainPanelInfo.height ) {

        if( ( p.mainPanelInfo.bottom - p.movingTreeInfo.bottom ) < 2 ) {

            if( ! p.localGlobal.scrollEvents.down ) {
                p.localGlobal.scrollEvents.down = true;

                setTimeout( verticalScroll, 0, { mainPanel: p.mainPanelInfo.element, scroll: 30 } );
            }
            
        } else {

            p.localGlobal.scrollEvents.down = false;
        }


        if( ( p.movingTreeInfo.top - p.mainPanelInfo.top ) < 2 ) {

            if( !p.localGlobal.scrollEvents.up ) {

                p.localGlobal.scrollEvents.up = true;

                setTimeout( verticalScroll, 0, { mainPanel: p.mainPanelInfo.element, scroll: -30 } );
            }

        } else {
            
            p.localGlobal.scrollEvents.up = false;
        }
    }
}

function handleTreeDrag( p ) {

    var localGlobal = globals;
    var localConfig = config;

    var movingTree = $(p.target);
    var movingTreeOffset = movingTree.offset();
    var movingTreeInfo = { top: movingTreeOffset.top,
                           height: movingTree.height(),
                           left: movingTreeOffset.left,
                           width: movingTree.width() };
    delete movingTreeOffset;

    var mainPanel = $('#mainPanel');
    var mainPanelOffset = mainPanel.offset();
    var mainPanelInfo = { top: mainPanelOffset.top,
                          height: mainPanel.height(),
                          left: mainPanelOffset.left,
                          width: mainPanel.width(),
                          scrollLeft: mainPanel.scrollLeft(),
                          scrollTop: mainPanel.scrollTop(),
                          element: mainPanel };
    delete movingPanelOffset;

    checkForMainPanelScroll( { localGlobal: localGlobal,
                               mainPanelInfo: mainPanelInfo,
                               movingTreeInfo: movingTreeInfo } );

    var closestCladeInfo = 
        findClosestClade(
            { x: movingTreeInfo.left, y: parseInt( movingTreeInfo.top ) + parseInt( movingTree.attr('rootY') ),
              closestClade: undefined, currentDistance: 1000000,
              scaleValue: { x: 1, y: 1 }, scaling: 'unscaled', clade: localGlobal.mainPanelTreeInfo.tree,
              offset: { y: mainPanelInfo.top - mainPanelInfo.scrollTop,
                        x: mainPanelInfo.left - mainPanelInfo.scrollLeft } } );

    if( closestCladeInfo.distance < 100 ) {

        var draggingInfo = localGlobal.draggingInfo;

        var closestClade = closestCladeInfo.clade;
        var mostRecentClade = draggingInfo.mostRecentClade;
        var closestCladeCoords = closestClade.coords;

        if( mostRecentClade && closestClade.id != mostRecentClade.id ) {

            var labelToMoveBack = localGlobal.labelInfo.labels[ mostRecentClade.id];

            translateLabel( { clade: mostRecentClade,
                              label: labelToMoveBack,
                              fontSize: localConfig.fontSize.value,
                              buttonRadius: 0,
                              labelBuffer: localConfig.labelBuffer.value,
                              scaling: 'unscaled',
                              scaleValue: { x:1, y:1 } } );
            
            mostRecentClade = undefined;
        }
        
        if( closestClade.children.length == 0 ) {

            var pathString = getCladePath( { clade: closestClade } );

            if( draggingInfo.hidingPath ) {

                draggingInfo.hidingPath.attr( { path: pathString } ).show();

            } else {

                draggingInfo.hidingPath = createTreePath( { string: pathString,
                                                            canvas: localGlobal.mainPanelCanvas,
                                                            attr: { stroke: 'white',
                                                                    "stroke-width": localConfig.pathWidth.value } } );
            }

            pathString = new StringBuffer();

            pathString.append("M").append(closestCladeCoords.unscaled.x + closestCladeCoords.unscaled.dx).append(" ")
                      .append(closestCladeCoords.y).append("L").append( movingTreeInfo.left - mainPanelInfo.left + mainPanelInfo.scrollLeft ).append(" ")
                      .append( movingTreeInfo.top - mainPanelInfo.top + mainPanelInfo.scrollTop + parseInt( movingTree.attr('rootY')) );

            if( draggingInfo.graftingPath ) {
                
                draggingInfo.graftingPath.attr( { path: pathString.toString() } ).show();

            } else {

                draggingInfo.graftingPath = createTreePath( { string: pathString.toString(),
                                                              canvas: localGlobal.mainPanelCanvas,
                                                              attr: { stroke: 'blue',
                                                                      "stroke-width": localConfig.pathWidth.value } } );
            }

            if( closestClade.name ) {
  
                var label =  localGlobal.labelInfo.labels[closestClade.id];

                label.attr( { x: movingTreeInfo.left - mainPanelInfo.left + mainPanelInfo.scrollLeft + (label.getBBox().width/2) + 5,
                              y: movingTreeInfo.top - mainPanelInfo.top + mainPanelInfo.scrollTop + parseInt(movingTree.attr('rootY')) } );
                
                draggingInfo.mostRecentClade = closestClade;
            }
            
        } else {
            
            if( draggingInfo.hidingPath ) { draggingInfo.hidingPath.hide(); }

            pathString = new StringBuffer();

            var x = closestCladeCoords.unscaled.x + closestCladeCoords.unscaled.dx;
            var boxY = movingTreeInfo.top - mainPanelInfo.top + mainPanelInfo.scrollTop + parseInt( movingTree.attr('rootY') );

            pathString.append("M").append(x).append(" ").append(closestCladeCoords.y).append("L").append(x).append(" ").append(boxY)
                      .append("M").append(x).append(" ").append(boxY).append("L").append( movingTreeInfo.left - mainPanelInfo.left + mainPanelInfo.scrollLeft)
                      .append(" ").append(boxY);


            if( draggingInfo.graftingPath ) {
                
                draggingInfo.graftingPath.attr( { path: pathString.toString() } ).show();

            } else {

                draggingInfo.graftingPath = createTreePath( { string: pathString.toString(),
                                                              canvas: localGlobal.skeletonCanvas,
                                                              attr: { stroke: 'blue',
                                                                      "stroke-width": localConfig.pathWidth.value } } );
            }
        }

   } else {

       hideVisualGraftingAnnotations();

   }
}

function getCladePath( p ) {

    var pathString = new StringBuffer();

    var coords = { x: p.clade.coords['unscaled'].x,
                  dx: ( p.clade.isRoot ) ? -20 : p.clade.coords['unscaled'].dx,
                   y: p.clade.coords.y };

    pathString.append( "M" ).append( coords.x ).append( " " ).append( coords.y ).append( "l" ).append( coords.dx ).append( " 0" );

    if( p.clade.children.length ) {

        var firstChildY = p.clade.children[0].coords.y;
        var lastChildY = p.clade.children[p.clade.children.length-1].coords.y;

        pathString.append( "M" ).append( coords.x ).append( " " ).append( firstChildY)
                  .append( "L" ).append( coords.x ).append( " " ).append( lastChildY );
    }

    return pathString.toString();
}

function handleGraftingTreeClick( p ) {
    
    if( p.which != 3 ) { return; }

    if( globals.draggingInfo.graftingPath ) {

        var graftingTree = $(p.target);

        makeContextMenu( { container: $('#mainPanel'), 
                           menuItems: [ { text: 'Graft',
                                          func: ajaxGraftOnto,
                                          params: { treeId: graftingTree.attr('treeId'),
                                                    treeType: graftingTree.attr('treeType') } } ],
                           x: p.pageX, y: p.pageY } );
    }
}

function setTreeDragging( p ) {
    globals.draggingInfo.currentlyDragging = true;
    $(p.target).mouseup( handleGraftingTreeClick );
}

function unsetTreeDragging( p ) { globals.draggingInfo.currentlyDragging = false; }

function handleReceivedTreeForRightPanel( ajaxResponse ) {

    var localGlobal = globals;

    var responseObj = eval( "(" + ajaxResponse + ")" );

    var tree = responseObj.tree;
    var treeId = responseObj.id;
    var treeType = responseObj.type;

    delete ajaxResponse;

    tree.isRoot = true;

    tree.meta = getTreeInfo( { 'clade': tree } );
    
    var canvasHeight = $('#rightPanel').height() / 2;
    var canvasWidth = $('#rightPanel').width() * .95;

    var divId = ( treeType == 'saved' ) ? 'saved'+treeId : treeId;
    
    $('#' + divId).append(
        makeEl('div').attr( { 'id': 'treeAction' + divId } ).append(
            makeEl('div').attr( { 'id': 'renderButton' + divId, 'class': 'fLeft width50 center smallText' } ).append(
                makeEl('a').attr( { 'href': 'javascript:void(0);' } )
                           .bind( 'click', { id: treeId, type: treeType, success: handleReceivedTreeForMainPanel }, getTreeForMainPanel )
                           .text( 'Render in Main Panel' ) ),
            makeEl('div').attr( { 'id': 'dragButton' + divId, 'class': 'fRight width50 center smallText' } ).append(
                makeEl('a').attr( { 'href': 'javascript:void(0);' } )
                           .bind( 'click', { divId: divId }, initializeDragGrafting )
                           .text( 'Graft onto Current Tree' ) ),
            makeEl('div').attr( { 'class': 'clear' } ) ),
        makeEl('div').attr( { 'id': 'visualWrapper' + divId, 'class': 'visualWrapper' } )
                     .height( canvasHeight )
                     .width( canvasWidth )
                     .css( { 'display': 'none' } )
                     .append( makeEl('div').attr( { 'id': 'raphaelContainer' + divId, 'class': 'absoluteFront' } ) ) )

    localGlobal.rightPanelCanvas[ divId ] = { 'canvas': Raphael( 'raphaelContainer' + divId, canvasWidth, canvasHeight ) };

    var generationSeparation = ( ( canvasWidth - 20 ) / ( tree.meta.generations ) );
    var nodeSeparation = ( canvasHeight / ( tree.meta.tips + 1 ) );

    var firstTip = { x: ( generationSeparation * ( tree.meta.generations - 1 ) + 20 ), //add 20 for root
                     y: nodeSeparation };


    var pathString = new StringBuffer();
    
    preRender( { clade: tree,
                 scaledBranches: false,
                 currentTip: firstTip,
                 scaleValue: { x: 1, y: 1 },
                 generationSeparation: generationSeparation,
                 nodeSeparation: nodeSeparation,
                 scaling: 'unscaled',
                 pathWidth: 1,
                 fontSize: 10,
                 buttonRadius: 0,
                 labelBuffer: 0,
                 pathStrings: pathString,
                 renderInfoFun: gatherNodeRenderInfo,
                 canvas: localGlobal.rightPanelCanvas[ divId ].canvas,
                 generation: tree.meta.generations } );


    createTreePath( { string: pathString.toString(),
                      canvas: localGlobal.rightPanelCanvas[ divId ].canvas,
                      attr: { stroke: 'black',
                              "stroke-width": 2 } } );

    $('#raphaelContainer' + divId).attr( {  'treeId': treeId, 
                                            'treeType': treeType,
                                            'rootY': tree.coords.y,
                                            'rootX': tree.coords['unscaled'].x } );

    $('#visualWrapper' + divId).show('slow');
}

function gatherNodeRenderInfo( p ) {

    addNodeToTreePath( { pathStrings: p.pathStrings,
                         clade: p.clade,
                         scaling: p.scaling } );
}

function addNodeToTreePath( p ) {

    var coords = { x: p.clade.coords[p.scaling].x,
                  dx: p.clade.coords[p.scaling].dx,
                   y: p.clade.coords.y };
    if( p.clade.isRoot ) {

        p.pathStrings.append( "M" ).append( coords.x ).append( " " ).append( coords.y ).append( "l-20 0" );

    } else {

        p.pathStrings.append( "M" ).append( coords.x ).append( " " ).append( coords.y ).append( "l" ).append( coords.dx ).append( " 0" );
    }

    if( p.clade.children.length ) {

        var firstChildY = p.clade.children[0].coords.y;
        var lastChildY = p.clade.children[p.clade.children.length-1].coords.y;

        p.pathStrings.append( "M" ).append( coords.x ).append( " " ).append( firstChildY)
                     .append( "L" ).append( coords.x ).append( " " ).append( lastChildY );
    }
}







function addMainPanelLabels( p ) {

    createProgressBar( { container: $('#mainPanel') } );

    mainPanelAsyncAddLabels( p );
}


function mainPanelAsyncAddLabels( p ) {

    if( globals.requestingTreeForMainPanel ) { removeProgressBar(); return; }

    $('#labelProgressBar').progressbar( 'option', 'value', ( p.index / p.labels.length ) * 100 );

    p.labelHolder[ p.labels[p.index].id ] =
        drawCladeLabel( { canvas: p.canvas, localConfig: p.localConfig, label: p.labels[p.index++] } );

    if( p.index < p.labels.length ) {

        setTimeout( mainPanelAsyncAddLabels, 0,
            { labels: p.labels, index: p.index, labelHolder: p.labelHolder, scaling: p.scaling,
              canvas: p.canvas, localConfig: p.localConfig } );

    } else {

        removeProgressBar();
    }
}

function removeProgressBar() {
    $('#labelProgressBar').empty().remove();
    $('#labelProgressBarHeader').remove();
}


function gatherMainPanelCladeInfo( p ) {

    var currentCoords = p.clade.coords;

    addNodeToTreePath( { pathStrings: p.pathStrings,
                         clade: p.clade,
                         scaling: p.scaling } );

    if( p.clade.name ) {

        handleLabel( { clade: p.clade,
                       labels: p.labels,
                       labelsToAdd: p.labelsToAdd,
                       fontSize: p.fontSize,
                       scaleValue: p.scaleValue,
                       buttonRadius: p.buttonRadius,
                       supportValueInfo: p.supportValueInfo,
                       scaling: p.scaling,
                       labelBuffer: p.labelBuffer } );
    }
}

function createAddSourceTreeButton() {

    var mainPanelOffset = $('#mainPanel').offset();

    $('#mainPanel').prepend(
            makeEl('a').attr( { 'class': 'smallText', href: 'javascript:void(0);' } )
                       .css( { position: 'absolute', left: mainPanelOffset.left + 5, top: mainPanelOffset.top + 5 } )
                       .text('Add Source Tree')
                       .click( renderAddSourceTreeDialogue ) );
}

function newickFileSelected() {
    $('#newickString').hide();
    $('#newickFileSelectedNotice').removeClass('hide');
    $('#cancelNewickFileUploadLink').removeClass('hide');
    $('#shadowboxSubmitButton').unbind('click').click( submitFileUploader );
}

function submitFileUploader() { globals.uploader.submit(); }
function newickStringAjaxUpload() { ajaxAddNewick(); }

function showNewickStringUploadDialogue() {
    $('#newickString').show();
    $('#newickFileSelectedNotice').addClass('hide');
    $('#cancelNewickFileUploadLink').addClass('hide');
    $('#shadowboxSubmitButton').unbind('click').click( newickStringAjaxUpload );
}

function hideVisualGraftingAnnotations() {

    var localGlobal = globals;
    var localConfig = config;
    var draggingInfo = localGlobal.draggingInfo;

    if( draggingInfo.hidingPath ) { draggingInfo.hidingPath.hide(); }
    if( draggingInfo.graftingPath ) { draggingInfo.graftingPath.hide(); }

    if( draggingInfo.mostRecentClade ) {

        var labelToMoveBack = localGlobal.labelInfo.labels[ draggingInfo.mostRecentClade.id ];

        translateLabel( { clade: draggingInfo.mostRecentClade,
                          label: labelToMoveBack,
                          fontSize: localConfig.fontSize.value,
                          buttonRadius: localConfig.buttonRadius.value,
                          labelBuffer: localConfig.labelBuffer.value,
                          scaling: 'unscaled',
                          scaleValue: { x:1, y:1 } } );

        draggingInfo.mostRecentClade = undefined;
    }
}


